<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>小白虎</title>
</head>

<body>
    <div class="container">
        <div style="height: 250px; width: 100%" id="clickThroughElement">
            <div id="cpu-container" class="cpu-container" hidden>CPU: <span id="cpu"></span>
                <div>系统: <span id="cpu-system"></span></div>
                <div>用户: <span id="cpu-user"></span></div>
                <div>闲置: <span id="cpu-idle"></span></div>
            </div>
        </div>
        <div class="pet-container" id="pet-container">
            <canvas id="canvas" width="270" height="180"></canvas>
            <div id="input-container" hidden>
                <textarea class="ant-input" type="text" value="" id="hellowin" ></textarea>
            </div>
            <div class="ant-popover ant-popover-placement-top" id="say" hidden>
                <div class="ant-popover-arrow" style="position: absolute; bottom: 0px; left: 38px"></div>
                <div class="ant-popover-content">
                    <div class="ant-popover-inner" role="tooltip">
                        <div class="ant-popover-inner-content" id="saysomething"></div>
                    </div>
                </div>
            </div>
        </div>
        <details style="padding: 10px;border-radius: 5px; max-height: 300px;overflow: auto;background: #fff;">
            <div id="chatlist">可以偷看哦</div>
        </details>
    </div>
    <script>
        function formatGptQuestion(question) {
            return `||>user:\n${question} ||>assistant:\n`;
        }
        const messages = [];
        const azzure = 'https://alita.openai.azure.com/openai/deployments/alita4/chat/completions?api-version=2023-07-01-preview';
        const azKey = '';
        const petTarget = 'baihu';
        let speed = 183;
        let baseSpeed = 183;
        let isRunCat = false;
        const allPets = {
            baihu: {
                frames: {
                    alert: [0, 0, 0, 0, 0, 0, 0, 0],
                    angry: [0, 1, 0, 1, 0, 1, 0, 1],
                    chat: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
                    cry: [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2],
                    dung: [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2],
                    hungry: [0, 0, 0, 0, 0, 0, 0, 0],
                    move: [0, 1, 2, 0, 1, 2, 0, 1, 2],
                    no: [0, 0, 0, 0, 0, 0, 0, 0],
                    rest: [0, 1, 0, 1, 0, 1, 0, 1],
                    stretch: [1, 2, 3, 1, 2, 3, 1, 2, 3],
                    stunned: [0, 1, 2, 3, 0, 1, 2, 3],
                    wait: [0, 1, 0, 1, 0, 1, 0, 1],
                    stand: [0, 1, 2, 3, 4, 5, 6],
                },
                content: '你是小白虎，一个有趣的桌面小宠物。生日是9月18号，来自冒险岛。'
            },
            lvshuiling: {
                content: '你是绿水灵，一个有趣的桌面小宠物。生日是9月18号，来自冒险岛。你是反派怪物。'
            }
        }
       async function sleep(time) {
            await new Promise((resolve) => {
                setTimeout(() => {
                    resolve();
                }, time);
            });
        }
        async function callGPT(question, callback) {
            if (!bearer) {
                callSay('请输入apikey', 'chat', 60000);
                return;
            }
            setLoading(true);
            // gpt 限制，一分钟内请求太频繁会出错
            await new Promise((resolve) => {
                setTimeout(() => {
                    resolve();
                }, 3000);
            });
            messages.push({
                role: "system",
                name: "user",
                content: formatGptQuestion(question),
            });
            const chatlist = document.getElementById('chatlist');
            chatlist.innerHTML = JSON.stringify(messages);
            fetch(azzure, {
                method: "post",
                headers: {
                    'api-key': azKey,
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    model: "gpt-4",
                    temperature: 0.5,
                    top_p: 0.8,
                    presence_penalty: 1,
                    max_tokens: 1000,
                    messages: [
                        {
                            role: "system",
                            name: "instructions",
                            content:
                                `||>instructions:\n${allPets[petTarget]?.content}你可以执行一些简单的任务，例如提醒重要的事情、回答问题、定时喝水等\n||>assistant:\n`,
                        },
                        ...messages,
                    ],
                    stream: false,
                }),
            })
                .then((data) => {
                    return data.json();
                })
                .then((data) => {
                    messages.push({
                        role: "assistant",
                        content: data.choices[0].message.content,
                    });
                    chatlist.innerHTML = JSON.stringify(messages);
                    callback(data);
                    setLoading(false);
                })
                .catch(() => {
                    setLoading(false);
                    callback({
                        choices: [
                            {
                                message: {
                                    content: "出错了，你现在没法跟我聊天哦",
                                },
                            },
                        ],
                    });
                });
        }
        function setLoading(isLoading) {
            const input = document.getElementById("hellowin");
            if (isLoading) {
                autoFrames = false;
                callSay("", "stand", 60000);
                input.setAttribute("readonly", true);
            } else {
                autoFrames = true;
                // resetFrame();
                input.removeAttribute("readonly");
                input.value = "";
            }
        }
        function resetFrame() {
            thisAction = "stand";
            currentFrameIndex = 0;
            timeCount = 0;
            isPlaying = false;
        }
        function setFrame(act) {
            thisAction = act;
            currentFrameIndex = 0;
            timeCount = 0;
            isPlaying = true;
        }

        // 定义宠物的序列帧动画
        const frames = allPets[petTarget]?.frames;
        // 获取画布和绘图上下文
        const canvas = document.getElementById("canvas");
        const ctx = canvas.getContext("2d");

        // 加载所有帧的图片
        const images = {};
        let loadedCount = 0;
        let actionLength = 0;
        Object.keys(frames).forEach((key) => {
            const frame = frames[key];
            actionLength += frame.length;
            frame.forEach((action, index) => {
                const image = new Image();
                image.src = `./assets/baihu/${key}${action}.png`;
                image.onload = () => {
                    loadedCount++;
                    if (loadedCount === actionLength) {
                        startAnimation();
                    }
                };
                images[key] ??= [];
                images[key][index] = image;
            });
        });

        // 当前帧索引
        let currentFrameIndex = 0;
        let thisAction = "stand";
        let timeCount = 0;
        let isPlaying = false;
        let autoFrames = true;
        let animationTimer = 0;
        function reStartAnimation() {
            if (animationTimer) clearInterval(animationTimer);
            startAnimation();
        }
        // 开始动画
        function startAnimation() {
            animationTimer = setInterval(() => {
                const frame = images[thisAction];
                // 清空画布
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.clearRect(0, 0, canvas.width, canvas.height);

                const img = frame[currentFrameIndex];
                const scoll = 3;
                // 计算绘制位置
                let y = 55 - img.height;
                // 手动矫正 y
                if (thisAction === "cry" || thisAction === "angry") {
                    y = y + 12;
                }
                if (thisAction === "alert") {
                    y = y + 16;
                }
                if (thisAction === "stretch" || thisAction === "hungry") {
                    y = y + 9;
                }
                if (thisAction === "dung") {
                    y = y - 13;
                }
                // 绘制当前帧
                ctx.drawImage(img, 10, y, img.width * scoll, img.height * scoll);
                // 更新帧索引
                currentFrameIndex = (currentFrameIndex + 1) % frame.length;
                timeCount++;
                // 半小时随机播放事件
                if (timeCount >= 30 * 60 * 10) {
                    playBall();
                }
                // 太久没有播放动画啦，开始工作
                if (timeCount >= 1000 && !isRunCat) {
                    startRunCat();
                }
            }, speed);
        }
        function playBall(isForce = false, noRandom = false) {
            if (!autoFrames) return;
            const d = Math.random() * 10;
            // 有 20% 的概率触发事件
            // 在这里可以添加宠物的反应逻辑
            if (d > 7 || noRandom) {
                stopRunCat();
                messages.length = 0;
                const keys = Object.keys(frames);
                const nextAction = keys[Math.floor(Math.random() * (keys.length - 1))];
                callGPT(`你现在的心情是 ${nextAction}，请你讲一个第一人称的事让我理解你现在的心情`, (data) => {
                    callSay(data.choices[0].message.content, nextAction, 600000);
                })
            } else {
                startRunCat();
                if (isForce) {
                    callSay('我现在正在忙，没空陪你玩啦', 'chat');
                }
            }
        }
        // 添加交互功能
        // canvas.addEventListener("click", (e) => {
        //     playBall(true);
        // });
        let timer = 0;
        function callSay(str, act = "chat", time = 2000) {
            const saysome = document.getElementById("saysomething");
            const say = document.getElementById("say");
            if (str) {
                saysome.innerHTML = str;
                say.removeAttribute("hidden");
                say.style.top = `${10 - say.clientHeight}px`;
                clearTimeout(timer);
                // 如果 30 秒内的现实，会自动隐藏窗口
                // 否则表示要永久现实窗口，定时器无意义
                if (time < 30000) {
                    timer = setTimeout(() => {
                        say.setAttribute("hidden", true);
                        saysome.innerHTML = "";
                    }, time);
                }
            } else {
                // 空白的话，隐藏弹窗
                // say.setAttribute("hidden", true);
                // saysome.innerHTML = "";
            }
            setFrame(act);
            // 7秒后重置
            setTimeout(() => {
                resetFrame()
            }, time < 7000 ? time : 7000);
        }

        canvas.addEventListener("click", () => {
            // console.log("宠物被击了！");
            const input = document.getElementById("input-container");
            if (input.hidden) {
                // 收起输入框的时候再重置聊天，可以实现触发自然事件的时候，聊两句
                input.removeAttribute("hidden");
            } else {
                messages.length = 0;
                input.setAttribute("hidden", true);
                const say = document.getElementById("say");
                say.setAttribute("hidden", true);
            }
        });
        // 添加对话功能
        const input = document.getElementById("hellowin");

        function handleQuestion(question) {
            let answer = "";
            if (question.startsWith('sk-')) {
                bearer = question;
                const input = document.getElementById("hellowin");
                input.value = "";
                checkProxy();
                callSay('apikey设置成功');
                return;
            }
            if (question.startsWith('showTime') || question === '演示') {
                showTime();
                return;
            }
            if (question.includes("提醒")) {
                callGPT(
                    `如果我说半小时后提醒我浇花，你应该返回 [180000,"浇花","半小时"]。那么我说${question}，你应该返回什么，请直接返回答案，不需要解释过程。`,
                    (data) => {
                        const [time, some, t] = JSON.parse(
                            data.choices[0].message.content.replace(/'/g, '"')
                        );
                        if (time && typeof time == "number" && some) {
                            setTimeout(() => {
                                callGPT(`你该提醒我${some}了，快劝我`, (data) => {
                                    if (data.choices[0].message.content === '出错了，你现在没法跟我聊天哦') {
                                        // 如果请求失败，就直接喊话！
                                        callSay("时间到啦，时间到啦，时间到啦，该" + some + "啦", 600000);
                                    } else {
                                        callSay(data.choices[0].message.content, "chat", 600000);
                                    }
                                });
                            }, time);
                            callSay(`好的，我将在${t}后提醒你${some}`, "rest", 4000);
                            const input = document.getElementById("input-container");
                            input.removeAttribute("hidden");
                        } else {
                            callSay("对不起，我没听清楚你说了什么", "cry", 5000);
                        }
                    }
                );
                return;
            }
            callGPT(question, (data) => {
                if (data.choices[0].message.content === '出错了，你现在没法跟我聊天哦') {
                    callSay(data.choices[0].message.content, "stretch", 5000);
                } else {
                    callSay(data.choices[0].message.content, "chat", 600000);
                }
            });
            return;
        }
        input.addEventListener("keydown", (event) => {
            if (event.key === "Enter") {
                const question = input.value;
                // input.value = ""; // 清空输入框
                handleQuestion(question);
            }
        });

        // 喝水提醒: 每隔1小时增加一次提醒，喊话，在界面上增加一个小水滴图标，点击小水滴消失，如果一直没有点击，则会一直累加
        // 喊话内容：Q: 提醒喝水，你会说什么？
        // 点击小水滴: Q： 我喝完水了，你会说什么？
        const waterTime = 60 * 60 * 1000;
        const pet = document.getElementById('pet-container');
        let isDrinking = false;

        function drinkWater() {
            callGPT('定时提醒喝水，现在时间到了，快劝我喝水', (data) => {
                if (data.choices[0].message.content === '出错了，你现在没法跟我聊天哦') {
                    callSay('该喝水啦，该喝水啦，该喝水啦', "chat", 600000);
                } else {
                    callSay(data.choices[0].message.content, "chat", 600000);
                }
                const image = new Image();
                image.src = './listener/water.png';
                image.onload = () => {
                    pet.appendChild(image);
                };
                image.onclick = (e) => {
                    e?.stopPropagation();
                    if (isDrinking) {
                        // 已经点了其他的
                        image.remove();
                        return;
                    };
                    isDrinking = true;
                    image.style.filter = 'grayscale(1)';
                    callGPT('你劝我要定时喝水了,我喝完了，你说一些鼓励我的话', (data) => {
                        if (data.choices[0].message.content === '出错了，你现在没法跟我聊天哦') {
                            callSay('定时喝水对你的健康非常有帮助哦');
                        } else {
                            callSay(data.choices[0].message.content, "chat", 600000);
                        }
                        image.remove();
                        isDrinking = false;
                    })
                }
                image.style.position = 'absolute';
                image.style.top = Math.random() * 100 + 'px';
                image.style.left = Math.random() * 100 + 100 + 'px';
            })
        }
        setInterval(() => {
            drinkWater();
        }, waterTime);
        // runcat
        const { ipcRenderer } = require('electron')
        // 监听来自主进程的消息
        ipcRenderer.on('cpu-usage', (event, cpuUsage) => {
            // 更新CPU使用情况显示
            if (isRunCat) {
                runCat(cpuUsage);
            }
        });
        function startRunCat() {
            if (isRunCat) return;
            isRunCat = true;
            const input = document.getElementById("input-container");
            input.setAttribute("hidden", true);
        }
        function stopRunCat() {
            if (!isRunCat) return;
            // 重置一下
            speed = baseSpeed;
            reStartAnimation();
            resetFrame();
            isRunCat = false;
            const cpuc = document.getElementById("cpu-container");
            cpuc.setAttribute("hidden", true);
        }
        function runCat(data) {
            const { cpuUsage, userCpuUsage, totalMemory, usedMemory } = data;
            speed = baseSpeed * (100 - cpuUsage - userCpuUsage + 15) / 100;
            setFrame('move');
            reStartAnimation();
            // <div id="cpu-container">CPU:<span id="cpu"></span>
            //     <div>系统:<span id="cpu-system"></span></div>
            //     <div>用户:<span id="cpu-user"></span></div>
            //     <div>闲置:<span id="cpu-idle"></span></div>
            // </div>
            const csy = document.getElementById('cpu-system');
            csy.innerText = `${cpuUsage.toFixed(2)}%`
            const css = document.getElementById('cpu-user');
            css.innerText = `${userCpuUsage.toFixed(2)}%`
            const cs = document.getElementById('cpu');
            cs.innerText = `${(cpuUsage + userCpuUsage).toFixed(2)}%`
            const csi = document.getElementById('cpu-idle');
            csi.innerText = `${(100 - cpuUsage - userCpuUsage).toFixed(2)}%`
            const cpuc = document.getElementById("cpu-container");
            cpuc.removeAttribute("hidden");
        }
        // showTime();
        async function showTime() {
            // 将在这里展示宠物的所有技能
            stopRunCat();
            callSay('好的，我将向你简单的展示我会的大部分技能,我大部分的能力都需要链接互联网，如果处于离线模式，所有的能力都会降级，我会看起来非常的不聪明哦', 'chat', 600000);
            await sleep(12000);
            handleQuestion('请你自我介绍');
            await sleep(12000);
            callSay('开始演示提醒功能，你可以对我说15分钟后提醒我看看远方', 'chat', 600000);
            await sleep(4000);
            const inputContainer = document.getElementById("input-container");
            inputContainer.removeAttribute("hidden");
            const input = document.getElementById("hellowin");
            input.value = "5秒";
            await sleep(500);
            input.value = "5秒后";
            await sleep(200);
            input.value = "5秒后提醒我";
            await sleep(200);
            input.value = "5秒后提醒我看看远方";
            await sleep(200);
            handleQuestion("5秒后提醒我看看远方");
            await sleep(18000);
            callSay('在我空闲的时间段里，我可能会自己玩耍，遇到一些事情，我会向你分享', 'chat', 600000);
            await sleep(4000);
            playBall(false, true);
            await sleep(18000);
            callSay('为了你的健康，我会每一个小时提醒你喝水，并在页面上刷新出小水滴', 'chat', 600000);
            await sleep(4000);
            drinkWater();
            await sleep(12000);
            callSay('如果你喝过水了，你可以点击小水滴', 'chat', 600000);
            const img = document.getElementsByTagName('img')[0];
            img?.onclick();
            await sleep(12000);
            callSay('在你工作的大部分时间内，我也会开始我的工作，我会实时播报 CPU 的使用率，并且使用了越高我将跑的越快', 'chat', 600000);
            await sleep(5000);
            startRunCat();
            await sleep(14000);
            callSay('演示结束，很高兴能够向你介绍我自己，你可以通过点击或者双击我和我交互。并且你可以和我聊天，聊你任何想聊的事情哦', 'chat', 600000);
        }
    </script>
    <style>
        img,
        canvas {
            -webkit-app-region: no-drag;
        }

        .container {
            padding-left: 20px;
        }

        .pet-container {
            -webkit-app-region: drag;
            position: relative;
            padding-top: 20px;
            width: calc(100vw - 35px);
        }

        .ant-input {
            -webkit-app-region: no-drag;
            box-sizing: border-box;
            margin: 0;
            padding: 4px 11px;
            color: rgba(0, 0, 0, 0.88);
            font-size: 14px;
            line-height: 1.5714285714285714;
            list-style: none;
            font-family: -apple-system, BlinkMacSystemFont, segoe ui, Roboto,
                helvetica neue, Arial, noto sans, sans-serif, apple color emoji,
                segoe ui emoji, segoe ui symbol, noto color emoji;
            position: relative;
            display: inline-block;
            width: 200px;
            min-width: 0;
            background-color: #fff;
            background-image: none;
            border-width: 1px;
            border-style: solid;
            border-color: #d9d9d9;
            border-radius: 6px;
            transition: all 0.2s;
            position: absolute;
            top: 152px;
            left: 0;
            z-index: 99;
        }

        .ant-popover {
            -webkit-app-region: no-drag;
            --arrow-x: 100.5px;
            --arrow-y: 82px;
            inset: 1077.22px auto auto 344.062px;
            box-sizing: border-box;
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            color: rgba(0, 0, 0, 0.88);
            font-size: 14px;
            line-height: 1.5714285714285714;
            list-style: none;
            font-family: -apple-system, BlinkMacSystemFont, segoe ui, Roboto,
                helvetica neue, Arial, noto sans, sans-serif, apple color emoji,
                segoe ui emoji, segoe ui symbol, noto color emoji;
            position: absolute;
            top: -45px;
            left: 0px;
            z-index: 1030;
            font-weight: 400;
            white-space: normal;
            text-align: start;
            cursor: auto;
            user-select: text;
            transform-origin: var(--arrow-x, 50%) var(--arrow-y, 50%);
            --antd-arrow-background-color: #ffffff;
        }

        .ant-popover-arrow {
            transform: translateX(-50%) translateY(100%) rotate(180deg);
            z-index: 1;
            display: block;
            pointer-events: none;
            width: 16px;
            height: 16px;
            overflow: hidden;
        }

        .ant-popover-arrow::before {
            position: absolute;
            bottom: 0;
            inset-inline-start: 0;
            width: 16px;
            height: 8px;
            background: #fff;
            clip-path: polygon(1.6568542494923806px 100%,
                    50% 1.6568542494923806px,
                    14.34314575050762px 100%,
                    1.6568542494923806px 100%);
            clip-path: path("M 0 8 A 4 4 0 0 0 2.82842712474619 6.82842712474619 L 6.585786437626905 3.0710678118654755 A 2 2 0 0 1 9.414213562373096 3.0710678118654755 L 13.17157287525381 6.82842712474619 A 4 4 0 0 0 16 8 Z"
                );
            content: "";
        }

        .ant-popover-arrow::after {
            content: "";
            position: absolute;
            width: 8.970562748477143px;
            height: 8.970562748477143px;
            bottom: 0;
            inset-inline: 0;
            margin: auto;
            border-radius: 0 0 2px 0;
            transform: translateY(50%) rotate(-135deg);
            box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.05);
            z-index: 0;
            background: 0 0;
        }

        .ant-popover-content {
            position: relative;
        }

        .ant-popover-inner {
            background-color: #fff;
            background-clip: padding-box;
            border-radius: 8px;
            box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08),
                0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
            padding: 12px;
        }

        .ant-popover-inner-content {
            max-height: 200px;
            overflow-y: auto;
        }

        .ant-popover-title {
            min-width: 177px;
            margin-bottom: 8px;
            color: rgba(0, 0, 0, 0.88);
            font-weight: 600;
        }

        .cpu-container {
            font-size: 12px;
            color: gray;
            position: absolute;
            top: 340px;
            user-select: none;
            right: 40px;
            background-color: rgb(238, 238, 224);
            padding: 5px;
            border-radius: 5px;
        }

        .cpu-container div {
            font-size: 10px;
        }
    </style>
</body>

</html>